package PrjHttpServ

import (
	"database/sql"
	"dgo/MyProj/PrjDBUtils"
	db_utils "dgo/goutils/db-utils"
	"dgo/goutils/utils"
	"errors"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"io/ioutil"
	"net/http"
	"strings"
)

const (
	EMPTY_STRING string = ""
)

type dbresRec struct {
	restype int    // 0, 1, 2
	groupid string // 分组
	conf    *wrapper.SuperValue
}

func newDBResRec(restype int, groupid string, conf *wrapper.SuperValue) *dbresRec {
	rval := &dbresRec{
		restype: restype,
		groupid: groupid,
		conf:    conf,
	}
	return rval

}

var (
	dbres_map utils.GSyncMapGroup
)

const (
	// 0:不存在就插入, 1:表示更新, 2:插入, 3:删除
	DBCOMM_UPTYPE_INSERTORUPDATE int = 0
	DBCOMM_UPTYPE_UPDATE         int = 1
	DBCOMM_UPTYPE_APPEND         int = 2
	DBCOMM_UPTYPE_DELETE         int = 3
)

func RegisterDBResStr(id string, jsonstr string) {
	v, err := wrapper.NewSVFromBuf([]byte(jsonstr))
	if err != nil {
		utils.Log.WarnTypef("STATE", "注册qry[%s]异常:%s, data:%s", id, err.Error(), jsonstr)
	}

	RegisterDBRes(id, v)
}

func RegisterDBResMap(resMap map[string]string) {
	for k, v := range resMap {
		RegisterDBResStr(k, v)
	}
}

func RegisterDBResMapPrefix(prefix string, resMap map[string]string) {
	for k, v := range resMap {
		RegisterDBResStr(prefix+k, v)
	}
}

func RegisterDBResListEx(prefix string, lst *wrapper.SuperValue, restype int, groupid string) int {
	if lst == nil || lst.Count() == 0 {
		return 0
	}

	r := 0
	lst.Range(func(key string, val *wrapper.SuperValue) bool {
		id := val.StringByName("id", "")
		if len(id) > 0 {
			RegisterDBResEx(prefix+id, val.ValueByName("conf"), restype, groupid)
			r++
		} else if len(key) > 0 {
			RegisterDBResEx(prefix+key, val, restype, groupid)
			r++
		}
		return true
	})
	return r
}

/*
*
[

	{"id":"xx", "conf":{}}, {"id":"xx", "conf":{}}

]

	{
	   "id":{},"id2":{}
	}
*/
func RegisterDBResList(prefix string, lst *wrapper.SuperValue, restype int, groupid string) int {
	return RegisterDBResListEx(prefix, lst, restype, groupid)
}

func RegisterDBResFromJson(prefix string, json *wrapper.SuperValue, restype int, groupid string) (int, error) {
	if json.IsArray() {
		return RegisterDBResList(prefix, json, restype, groupid), nil
	} else {
		lst := json.ValueByName("list")
		if lst == nil {
			lst = json.ValueByName("plugins")
		}
		if lst != nil {
			return RegisterDBResList(prefix, lst, restype, groupid), nil
		}
		return RegisterDBResList(prefix, json, restype, groupid), nil
	}
}

func RegisterDBResFromFile(prefix string, filename string, restype int, groupid string) (int, error) {
	json, err := wrapper.NewSVFromFile(filename)
	if err != nil {
		return 0, err
	}
	return RegisterDBResFromJson(prefix, json, restype, groupid)
}

func DownResFromServ(url string, saveAs string, encrptkey string) error {
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode == 404 || resp.StatusCode == 503 {
		return errors.New(resp.Status)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	{
		_, err := utils.NewFileData(saveAs, body)
		if err != nil {
			return err
		}
	}

	return nil
}

func RegisterDBResFromURL(prefix string, url string, saveAs string, restype int, groupid string) (int, error) {
	resp, err := http.Get(url)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()
	if resp.StatusCode == 404 || resp.StatusCode == 503 {
		return 0, errors.New(resp.Status)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, err
	}

	json, err := wrapper.NewSVFromBuf(body)
	if err != nil {
		return 0, err
	}

	if json.IntByName("code", 0) == -1 {
		return 0, fmt.Errorf("[%d]%s", json.IntByName("errcode", 0), json.StringByName("msg", ""))
	}

	if len(saveAs) > 0 {
		_, err := utils.NewFileData(saveAs, body)
		if err != nil {
			return 0, err
		}
	}

	return RegisterDBResFromJson(prefix, json, restype, groupid)
}

func DBResClean(grupid string) {
	dbres_map.Range(func(key, value interface{}) bool {
		if value.(*dbresRec).groupid == grupid {
			dbres_map.Remove(key)
		}
		return true
	})
}

func DBResCleanEx(restype int, grupid string) {
	dbres_map.Range(func(key, value interface{}) bool {
		rec := value.(*dbresRec)
		if rec.restype == restype && rec.groupid == grupid {
			dbres_map.Remove(key)
		}
		return true
	})
}

func RegisterDBRes(id string, conf *wrapper.SuperValue) {
	dbres_map.Set(id, newDBResRec(0, EMPTY_STRING, conf))
}

func RegisterDBResEx(id string, conf *wrapper.SuperValue, restype int, groupid string) {
	dbres_map.Set(id, newDBResRec(restype, groupid, conf))
}

func DBResExists(id string) bool {
	v := dbres_map.Get(id, nil)
	return v != nil
}

func GetDBRes(id string) *wrapper.SuperValue {
	v := dbres_map.Get(id, nil)
	if v == nil {
		return nil
	} else {
		return v.(*dbresRec).conf
	}
}

/*
**

	Exec,
*/
func GetDBResSQLEx(res *wrapper.SuperValue, sec string, args *wrapper.SuperValue) string {
	if res == nil {
		return ""
	}
	conf := res.ValueByName(sec)
	if conf == nil {
		return ""
	}
	var sql string
	if conf.IsObject() {
		sql = conf.StringByName("sql", "")
	} else {
		sql = conf.String()
	}

	if args != nil && args.Count() > 0 {
		args.Range(func(key string, val *wrapper.SuperValue) bool {
			id := key
			if len(id) == 0 {
				id = val.StringByName("id", "")
				if len(id) > 0 {
					id = fmt.Sprintf("$%s$", id)
					sql = strings.ReplaceAll(sql, id, val.StringByName("val", ""))
				}
			} else {
				id = fmt.Sprintf("$%s$", id)
				if val.IsObject() {
					sql = strings.ReplaceAll(sql, id, val.StringByName("val", ""))
				} else {
					sql = strings.ReplaceAll(sql, id, val.String())
				}
			}
			return true
		})
		return sql
	}

	return sql

}

func GetDBResSQL(id, sec string, args *wrapper.SuperValue) string {
	res := GetDBRes(id)
	return GetDBResSQLEx(res, sec, args)

}

func ProjRows2List(json *wrapper.SuperValue, rows *sql.Rows, jsonfields ...string) error {
	vals, cols, err := db_utils.ExtractRowsAndColumns(rows)
	if err != nil {
		return err
	}
	if len(jsonfields) == 0 {
		return PrjDBUtils.JsonCopyFromRowsAndColumnWithCb3(json, vals, cols, nil)
	} else {
		return PrjDBUtils.JsonCopyFromRowsAndColumnWithCb3(json, vals, cols, func(rec *wrapper.SuperValue, k *string, v *interface{}, rowval []db_utils.SqlValue, ignore *bool) {
			if utils.StrIndex(*k, jsonfields...) >= 0 {
				v1 := *v
				if buf, ok := v1.([]byte); ok {
					json, err := wrapper.NewSVFromBuf(buf)
					if err != nil {
						*v = nil
					}
					*v = json
				}
			}

		})
	}

}
